/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package model;

import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JOptionPane;

/**
 *
 * @author jadson
 */
public class SintaticalAnalyserSimple {

    private List<Token> listadeTokens;
    private List<Hashtable> pilhaEscopo;
    //  private List<Token> listadePalavrasReservadas;
    private int indiceToken = 0;
    private int indiceEscopo = -1;
    private Hashtable<String, Token> simbolTable;
    //  private int noprograma = 0;
    private int noidentificador = 0;
    private int noabrechave = 0;
    private int nofechaChave = 0;
    private int noPontoeVirgula = 0;
    private Token tokenaux;
    private Token tokenAtribuicao;
    private Token tokenFuncao;
    private Token funcaoParametros;
    private int iterador = 0;
    private LinkedList<String> erros;
    private LinkedList<Token> parametros;
    

    
    
    public SintaticalAnalyserSimple(List<Token> lista) {
        listadeTokens = lista;
        pilhaEscopo = new LinkedList<Hashtable>();
        erros = new LinkedList<String>();
        parametros = new LinkedList<Token>();
        Token cifrão = new Token("$", 0, "fim de analise sitática");
        listadeTokens.add(cifrão);
        imprimeListaToken();
        // analyseListTokens();
        // this.imprimeListaToken();
    }

    public void estrutura(Token token) {
        tokenaux = token;
        // System.out.println("" + token.getToken());
        if (tokenaux.getTipo().equals("Palavra Reservada")) {
            System.out.println("passou e era Palavra Reservada");
            //constantes(tokenaux);

        } else if (tokenaux.getTipo().equals(";")) {
            System.out.println("passou e era o ';'");
            tokenaux = proximoToken();
        }
        noidentificador = 0;
        constantes(tokenaux);
        noPontoeVirgula = 0;
        noabrechave = 0;
        nofechaChave = 0;
        noidentificador = 0;
        variaveis(tokenaux);
        registro();
        noidentificador = 0;
        noPontoeVirgula = 0;
        renomearTipo();
        funcao();
    }

    /* public void chamadaFuncao(){
     if(tokenaux.getToken().equals("Identificador")){
     tokenaux = proximoToken();
     if(tokenaux.getToken().equals("(")){
     parametros();
     }
     }
     
     }*/
    public void parametros() {
        
        if (tokenaux.getTipo().equals("Identificador")) {
            if (simbolTable.get(tokenaux.getToken()) == null && pilhaEscopo.get(0).get(tokenaux.getToken()) == null) {
                parametros.add(tokenaux);
                System.out.println("ERRO: Parametro " + tokenaux.getToken() + " passado não declarado");
                erros.add("ERRO: Parametro " + tokenaux.getToken() + " passado não declarado");
            } else {
                if (simbolTable.get(tokenaux.getToken()) != null) {
                    parametros.add(simbolTable.get(tokenaux.getToken()));
                } else {
                    if (pilhaEscopo.get(0).get(tokenaux.getToken()) != null) {
                        
                        parametros.add((Token) pilhaEscopo.get(0).get(tokenaux.getToken()));
                    
                    }
                }

            }

            System.out.println("Identificador encontrado");
            tokenaux = proximoToken();
            parametroFatorado();
        } else if (tokenaux.getToken().equals(")")) {
            System.out.println(") Encontrado");
            tokenaux = proximoToken();
            if (tokenaux.getToken().equals(";")) {
                try{
                
                if(funcaoParametros.getParametrosFunção()==null){
                    System.out.println("Função sem parâmetros");
                }
                else{
                    if (funcaoParametros.getParametrosFunção().size() != parametros.size()) {
                    System.out.println("ERRO: Quantidade de parametros da chamada diferente do esperado");
                    erros.add("ERRO: Quantidade de parametros da chamada diferente do esperado");
                } else {
                    for (int i = 0; i < parametros.size(); i++) {
                        if(funcaoParametros.getParametrosFunção()==null){
                            System.out.println("Função não possui parametros");
                            erros.add("ERRO: Função declarada sem parâmetros");
                            break;
                        }
                        else{
                          if (!funcaoParametros.getParametrosFunção().get(i).getTipoDeclarado().equals(parametros.get(i))) {
                            System.out.println("ERRO: parametro não compatível com declaração da função");
                            erros.add("ERRO: parametro não compatível com declaração da função");
                            break;
                        }  
                        }
                        

                    }

                }
                
                }
                                                
                }catch(NullPointerException r){
                    System.out.println("Função sem parâmetros");
                    
                }
                
                
                System.out.println("; Encontrado");
                if(parametros !=null){
                    parametros.clear();
                }
                
                funcaoParametros = null;
                tokenaux = proximoToken();
            }
        }
    }

    public void parametroFatorado() {
        if (tokenaux.getToken().equals(",")) {
            System.out.println(", Encontrado");
            tokenaux = proximoToken();
            parametros();
        } else if (tokenaux.getToken().equals(")")) {
            System.out.println(") Encontrado");
            tokenaux = proximoToken();
            if (tokenaux.getToken().equals(";")) {
                if(funcaoParametros.getParametrosFunção()==null){
                    System.out.println("ERRO: Função declarada sem parâmetros");
                    erros.add("ERRO: Função declarada sem parâmetros");
                }
                else{
                    if (funcaoParametros.getParametrosFunção().size() != parametros.size()) {
                    System.out.println("ERRO: Quantidade de parametros da chamada diferente do esperado");
                    erros.add("ERRO: Quantidade de parametros da chamada diferente do esperado");
                } else {
                    for (int i = 0; i < parametros.size(); i++) {
                        if(funcaoParametros.getParametrosFunção()==null){
                            System.out.println("Função não possui parametros");
                            break;
                        }
                        else{
                          if (!funcaoParametros.getParametrosFunção().get(i).getTipoDeclarado().equals(parametros.get(i))) {
                            System.out.println("ERRO: parametro não compatível com declaração da função");
                            erros.add("ERRO: parametro não compatível com declaração da função");
                            break;
                        }  
                        }
                        

                    }

                }
                
                }
                System.out.println("; Encontrado");
                parametros.clear();
                funcaoParametros = null;
                System.out.println("; Encontrado");
                tokenaux = proximoToken();
            }
        }
    }

    public void funcao() {
        if (tokenaux.getToken().equals("funcao")) {
            System.out.println("Bloco Funcao declarado");
            tokenaux = proximoToken();
            corpo();

        } else {
            System.out.println("Bloco de Funcao não declarado");
            while (!tokenaux.getToken().equals("principal")) {
                tokenaux = proximoToken();
            }
        }
    }

    public void corpo() {
        Token tokenteste = tokenaux;
        tipoFuncao(tokenaux);

        if (tokenteste.equals(tokenaux)) {
            if (tokenaux.getToken().equals("principal")) {
                System.out.println("principal encontrado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: Esperado 'principal'");
                erros.add("ERRO: Esperado 'principal'");
            }
            funcaoCorpoPrincipal();
        } else {
            indiceToken--;                     //foi pra tipos funções
            tokenaux = tokenteste;

            tipoFuncao(tokenaux);
            tokenFuncao = tokenaux;

            if (tokenaux.getTipo().equals("Identificador")) {
                //if(indiceEscopo!=0){
                if ((pilhaEscopo.get(0).get(tokenaux.getToken()) != null)) {
                    System.out.println("ERRO: Função " + tokenaux.getToken() + " já declarado neste escopo!");
                    erros.add("ERRO: Função " + tokenaux.getToken() + " já declarado neste escopo!");
                } else {
                    pilhaEscopo.get(0).put(tokenaux.getToken(), tokenaux);
                }
                // simbolTable.put(tokenaux.getToken(), tokenaux);
                indiceEscopo++;
                pilhaEscopo.add(new Hashtable<String, Token>());
                simbolTable = pilhaEscopo.get(indiceEscopo);

                //}
                System.out.println("Identificador " + tokenaux.getToken() + " encontrado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: Identificador esperado");
                erros.add("ERRO: Identificador esperado");
            }
            listaParametros();
            funcaoCorpo();
            funcao();
        }

    }

    public void listaParametros() {
        if (tokenaux.getToken().equals("(")) {
            System.out.println("( encontrado!");
            tokenaux = proximoToken();
        } else {
            System.out.println("ERRO: ( era esperado");
            erros.add("ERRO: ( era esperado");
        }
        parametroFuncao();
    }

    public void parametroFuncao() {
        Token tokenteste = tokenaux;
        tipo(tokenaux);

        if (tokenteste.equals(tokenaux)) {
            if (tokenaux.getToken().equals(")")) {  // foi ')'
                System.out.println(") encontrado");
                tokenaux = proximoToken();

            } else {
                System.out.println("ERRO: ) esperado");
                erros.add("ERRO: ) era esperado");
            }
        } else {
            indiceToken--;
            tokenaux = tokenteste;
            tipoParametros();
        }
    }

    public void tipoParametros() {
        tipo(tokenaux);
        if (tokenaux.getTipo().equals("Identificador")) {
            tokenFuncao.inserirParametro(tokenaux);
            System.out.println("Identificador encontrado");
            tokenaux = proximoToken();
        } else {
            System.out.println("ERRO: Identificador esperado");

        }
        tipoNomeFatorado();

    }

    public void tipoNomeFatorado() {
        if (tokenaux.getToken().equals(",")) {
            System.out.println(", Encontrado");
            tokenaux = proximoToken();
            tipoParametros();
        } else {
            // System.out.println("ERRO: esperado o ','");

            Token tokenteste = tokenaux;
            tipo(tokenaux);

            if (tokenteste.equals(tokenaux)) {

                if (tokenaux.getToken().equals(")")) {
                    if (pilhaEscopo.get(0).get(tokenFuncao) == null) {
                        pilhaEscopo.get(0).put(tokenFuncao.getToken(), tokenFuncao);
                    } else {
                        pilhaEscopo.get(0).remove(tokenFuncao.getToken());
                        pilhaEscopo.get(0).put(tokenFuncao.getToken(), tokenFuncao);
                    }
                    System.out.println(") Encontrado");
                    tokenaux = proximoToken();
                } else {
                    System.out.println("ERRO: ) não encontrado");
                }
            } else {
                System.out.println("ERRO: esperado o ','");
                indiceToken--;
                tokenaux = tokenteste;
                tipoParametros();
            }

        }



    }

    public void funcaoCorpo() {
        if (tokenaux.getToken().equals("{")) {
            System.out.println("'{' Encontrado");
            tokenaux = proximoToken();
        } else {
            System.out.println("ERRO: { não encontrado");
        }
        variaveis(tokenaux);
        comandos();
        retorno();

        if (tokenaux.getToken().equals("}")) {
            pilhaEscopo.remove(indiceEscopo);
            indiceEscopo--;
            simbolTable = pilhaEscopo.get(indiceEscopo);
            System.out.println("'}' Encontrado");
            System.out.println("Fim do bloco de funções");
            tokenaux = proximoToken();
        } else {
            System.out.println("ERRO: } não encontrado");
        }
    }

    public void comandos() {

        if (tokenaux.getToken().equals("se") || tokenaux.getToken().equals("para") || tokenaux.getToken().equals("enquanto") || tokenaux.getToken().equals("leia") || tokenaux.getToken().equals("escreva") || tokenaux.getTipo().equals("Identificador")) {
            opcoesComandos();
            comandos();
        } else if (tokenaux.getToken().equals("++") || tokenaux.getToken().equals("--")) {
            atribuicoes();
        } else {
            System.out.println("Bloco 'comandos' não inicializado");
        }
    }

    public void opcoesComandos() {
        if (tokenaux.getToken().equals("se")) {
            System.out.println("Palavra 'se' Identificada");
            tokenaux = proximoToken();
            if (tokenaux.getToken().equals("(")) {
                System.out.println("'(' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: '(' não identificado");
            }
            escolha_expressao();
            if (tokenaux.getToken().equals(")")) {
                System.out.println("')' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: ')' não identificado");
            }
            if (tokenaux.getToken().equals("{")) {
                System.out.println("'{' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: '{' não identificado");
            }
            comandos();
            if (tokenaux.getToken().equals("}")) {
                System.out.println("'}' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: '}' não identificado");
            }
            senao();

        } else {
            System.out.println("Palavra 'se' não Encontrada");
        }


        if (tokenaux.getToken().equals("para")) {
            System.out.println("Palavra 'para' Identificada");
            tokenaux = proximoToken();

            if (tokenaux.getToken().equals("(")) {
                System.out.println("'(' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: '(' não identificado");
            }

            atribuicoes();

            if (tokenaux.getToken().equals(";")) {
                System.out.println(" ';' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: ';' não identificado");
            }

            escolha_expressao();

            if (tokenaux.getToken().equals(";")) {
                System.out.println(" ';' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: ';' não identificado");
            }

            atribuicoes();

            if (tokenaux.getToken().equals(")")) {
                System.out.println("')' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: ')' não identificado");
            }


            if (tokenaux.getToken().equals("{")) {
                System.out.println("'{' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: '{' não identificado");
            }

            comandos();


            if (tokenaux.getToken().equals("}")) {
                System.out.println("'}' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: '}' não identificado");
            }


        } else {
            System.out.println("Palavra 'para' não Encontrada");
        }



        if (tokenaux.getToken().equals("enquanto")) {
            System.out.println("Palavra 'enquanto' Identificada");
            tokenaux = proximoToken();

            if (tokenaux.getToken().equals("(")) {
                System.out.println("'(' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: '(' não identificado");
            }

            condicaoEnquanto();

            if (tokenaux.getToken().equals(")")) {
                System.out.println("')' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: ')' não identificado");
            }


            if (tokenaux.getToken().equals("{")) {
                System.out.println("'{' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: '{' não identificado");
            }

            comandos();


            if (tokenaux.getToken().equals("}")) {
                System.out.println("'}' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: '}' não identificado");
            }

        } else {
            System.out.println("Palavra 'enquanto' não Encontrada");
        }


        if (tokenaux.getToken().equals("leia")) {
            System.out.println("Palavra 'leia' Identificada");
            tokenaux = proximoToken();

            if (tokenaux.getToken().equals("(")) {
                System.out.println("'(' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: '(' não identificado");
            }

            fatorLeia();

            if (tokenaux.getToken().equals(";")) {
                System.out.println(" ';' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: ';' não identificado");
            }

        } else {
            System.out.println("Palavra 'leia' não Encontrada");
        }



        if (tokenaux.getToken().equals("escreva")) {
            System.out.println("Palavra 'escreva' Identificada");
            tokenaux = proximoToken();

            if (tokenaux.getToken().equals("(")) {
                System.out.println("'(' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: '(' não identificado");
            }

            fatorEscrita();

            if (tokenaux.getToken().equals(";")) {
                System.out.println(" ';' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: ';' não identificado");
            }

        } else {
            System.out.println("Palavra 'escreva' não Encontrada");
        }


        if (tokenaux.getTipo().equals("Identificador")) {
            System.out.println("Palavra 'Identificador' Identificada");
            Token aux = new Token();
            aux = proximoToken();
            indiceToken--;
            if (aux.getToken().equals("(")) {
                tokenaux = proximoToken();
                if (pilhaEscopo.get(0).get(tokenaux.getToken()) != null) {
                    funcaoParametros = (Token) pilhaEscopo.get(0).get(tokenaux.getToken());
                } else {
                    // funcaoParametros = tokenaux;
                    System.out.println("ERRO: Função chamada: " + tokenaux.getToken() + " não declarada");
                    erros.add("ERRO: Função chamada: " + tokenaux.getToken() + " não declarada");
                }
                tokenaux = proximoToken();
                complementoFuncaoOuAtribuicao();
            } else {
                atribuicoes();

            }

        } else {
            if (tokenaux.getToken().equals("++") || tokenaux.getToken().equals("--")) {
                atribuicoes();
            }
            //System.out.println("Palavra 'Identificador' não Encontrada");
        }
    }

    public void complementoFuncaoOuAtribuicao() {
        parametros = new LinkedList<Token>();
        if (tokenaux.getToken().equals("(")) {
            System.out.println("'(' Encontrado");
            tokenaux = proximoToken();
            parametros();
        } else {
            complementoIdAtribuicao();
        }

    }

    public void escolha_expressao() {
        if (tokenaux.getTipo().equals("Identificador")) {
            System.out.println("Identificador " + tokenaux.getToken() + " encontrado");
            expressaoRelacional();
        } else if (tokenaux.getToken().equals("verdadeiro") || tokenaux.getToken().equals("falso")) {
            expressaoBooleana();
        }
    }

    public void expressaoRelacional() {
        expressaoAritmetica();
        operadorRelacional();
        expressaoAritmetica();
        complementoParaLogica();

    }

    public void operadorRelacional() {
        if (tokenaux.getToken().equals("<")) {
            System.out.println("Operador < encontrado");
            tokenaux = proximoToken();
        } else if (tokenaux.getToken().equals(">")) {
            System.out.println("Operador > encontrado");
            tokenaux = proximoToken();
        } else if (tokenaux.getToken().equals("<=")) {
            System.out.println("Operador <= encontrado");
            tokenaux = proximoToken();
        } else if (tokenaux.getToken().equals(">=")) {
            System.out.println("Operador >= encontrado");
            tokenaux = proximoToken();
        } else if (tokenaux.getToken().equals("==") || tokenaux.getToken().equals("!=")) {
            operadorRelacionalIgualdade();
        }
    }

    public void termoAritmetico() {
        fator();
        complementoFator();
    }

    public void expressaoBooleana() {

        if (tokenaux.getToken().equals("verdadeiro")) {
            System.out.println("Verdadeiro encontrado");
            tokenaux = proximoToken();
            complementoExpressaoBooleana();
        } else if (tokenaux.getToken().equals("falso")) {
            System.out.println("Falso encontrado");
            tokenaux = proximoToken();
            complementoExpressaoBooleana();

        }
    }

    public void complementoExpressaoBooleana() {

        if (tokenaux.getToken().equals("==") || tokenaux.getToken().equals("!=")) {
            operadorRelacionalIgualdade();
            if (tokenaux.getTipo().equals("Identificador")) {
                tokenaux = proximoToken();
                complementoParaLogica();
            }

        }

    }

    public void operadorRelacionalIgualdade() {
        if (tokenaux.getToken().equals("==")) {
            System.out.println("Operador " + tokenaux.getToken() + " encontrado");
            tokenaux = proximoToken();
        } else if (tokenaux.getToken().equals("!=")) {
            System.out.println("Operador " + tokenaux.getToken() + " encontrado");
            tokenaux = proximoToken();
        }
    }

    public void complementoParaLogica() {
        if (tokenaux.getToken().equals("||") || tokenaux.getToken().equals("&&")) {
            operadorLogico();
            escolha_expressao();
        }

    }

    public void operadorLogico() {

        if (tokenaux.getToken().equals("||")) {
            System.out.println("Operador OU encontrado");
            tokenaux = proximoToken();
        } else if (tokenaux.getToken().equals("&&")) {

            System.out.println("Operador AND encontrado");
            tokenaux = proximoToken();

        }

    }

    public void atribuicoes() {
        if (tokenaux.getTipo().equals("Identificador")) {
            System.out.println("Identificador " + tokenaux.getToken() + " encontrado");
            if (tokenaux.getTipo().equals("Identificador")) {
                if (simbolTable.get(tokenaux.getToken()) == null && pilhaEscopo.get(0).get(tokenaux.getToken()) == null) {
                    System.out.println("ERRO variavel " + tokenaux.getToken() + " não declarada");
                    erros.add("ERRO variavel " + tokenaux.getToken() + " não declarada");
                } else {
                    if (pilhaEscopo.get(0).get(tokenaux.getToken()) != null) {
                        tokenAtribuicao = (Token) pilhaEscopo.get(0).get(tokenaux.getToken());
                    }
                    if (simbolTable.get(tokenaux.getToken()) != null) {
                        tokenAtribuicao = simbolTable.get(tokenaux.getToken());
                    }

                }

                tokenaux = proximoToken();

                complementoIdAtribuicao();
            }
        } else if (tokenaux.getToken().equals("++") || tokenaux.getToken().equals("--")) {

            incrementoDecremento();

            if (tokenaux.getTipo().equals("Identificador")) {
                System.out.println("Identificador encontrado");
                tokenaux = proximoToken();
            }
        }

    }

    public void complementoIdAtribuicao() {

        if (tokenaux.getToken().equals("[") || tokenaux.getToken().equals("=") || tokenaux.getToken().equals(".")) {

            complementoReferenciaVariavelAtrib();

        } else if (tokenaux.getToken().equals("++") || tokenaux.getToken().equals("--")) {
            incrementoDecremento();
        }
    }

    public void complementoReferenciaVariavelAtrib() {

        if (tokenaux.getToken().equals("[")) {
            System.out.println("Delimitador '[' Identificado");
            tokenaux = proximoToken();

            expressaoAritmetica();

            if (tokenaux.getToken().equals("]")) {
                System.out.println("Delimitador ']' Identificado");
                tokenaux = proximoToken();

                matriz();

                if (tokenaux.getToken().equals("=")) {
                    System.out.println("Operador '=' Identificado");
                    tokenaux = proximoToken();

                    segundoMembroAtribuicao();

                }
            }

        } else if (tokenaux.getToken().equals("=")) {

            System.out.println("Operador '=' Identificado");
            tokenaux = proximoToken();

            segundoMembroAtribuicao();

        } else if (tokenaux.getToken().equals(".")) {
            System.out.println("Operador '.' Identificado");
            tokenaux = proximoToken();

            if (tokenaux.getTipo().equals("Identificador")) {
                System.out.println("Identificador Encontrado");
                tokenaux = proximoToken();

                if (tokenaux.getToken().equals("=")) {
                    System.out.println("Operador '=' Identificado");
                    tokenaux = proximoToken();

                    segundoMembroAtribuicao();
                }
            }
        }

    }

    public void segundoMembroAtribuicao() {
        String auxiliarVerificadora;
        if (tokenaux.getTipo().equals("Identificador")) {
            
            if (simbolTable.get(tokenaux.getToken()) == null && pilhaEscopo.get(0).get(tokenaux.getToken()) == null) {
                System.out.println("ERRO: Variavel " + tokenaux.getToken() + " não declarada");
                erros.add("ERRO: Variavel " + tokenaux.getToken() + " não declarada");
            }
            auxiliarVerificadora = tokenaux.getToken();
            tokenaux = proximoToken();
            if (tokenaux.getToken().equals("(")) {
                
                if (pilhaEscopo.get(0).get(auxiliarVerificadora) == null) {
                    System.out.println("ERRO: Funcao " + auxiliarVerificadora + " não declarada");
                    erros.add("ERRO: Funcao " + auxiliarVerificadora + " não declarada");
                }
                else{
                    funcaoParametros = (Token)pilhaEscopo.get(0).get(auxiliarVerificadora);
                }
                tokenaux = proximoToken();
                parametros();
            } else {
              //  tokenaux = listadeTokens.get(indiceToken--);
                while(listadeTokens.get(indiceToken).getToken()!= auxiliarVerificadora){
                    indiceToken--;
                }
                tokenaux = listadeTokens.get(indiceToken);
                expressaoAritmetica();
            }


        } else if (tokenaux.getToken().equals("++") || tokenaux.getToken().equals("--")) {

            incrementoDecremento();

            if (tokenaux.getTipo().equals("Identificador")) {
                try {
                    if (tokenAtribuicao.getTipoDeclarado().equals(simbolTable.get(tokenaux.getToken()).getTipoDeclarado())) {
                        System.out.println("Atribuição realizada com sucesso!");
                    } else {
                        System.out.println("ERRO: Tipos Incompativeis Esperado: " + tokenAtribuicao.getTipoDeclarado() + " Encontrado:" + simbolTable.get(tokenaux.getToken()).getTipoDeclarado());
                        erros.add("ERRO: Tipos Incompativeis Esperado: " + tokenAtribuicao.getTipoDeclarado() + " Encontrado:" + simbolTable.get(tokenaux.getToken()).getTipoDeclarado());
                    }
                } catch (NullPointerException e) {
                    System.out.println("ERRO: Variável " + tokenaux.getToken() + " não declarada");
                    erros.add("ERRO: Variável " + tokenaux.getToken() + " não declarada");
                }

                System.out.println("Identificador Encontrado");
                tokenaux = proximoToken();
            }
        } else if (tokenaux.getTipo().equals("CARACTERE BEM FORMADO")) {
            String auxiliar = "caractere";
            if (tokenAtribuicao.getTipoDeclarado().equals(auxiliar)) {
                System.out.println("Atribuição realizada com sucesso!");
            } else {
                System.out.println("ERRO: Tipos Incompativeis Esperado: " + tokenAtribuicao.getTipoDeclarado() + " Encontrado: " + auxiliar);
                erros.add("ERRO: Tipos Incompativeis Esperado: " + tokenAtribuicao.getTipoDeclarado() + " Encontrado: " + auxiliar);
            }
            System.out.println("Caractere encontrado");
            tokenaux = proximoToken();

        } else if (tokenaux.getTipo().equals("String")) {
            String auxiliar = "cadeia";
            if (tokenAtribuicao.getTipoDeclarado().equals(auxiliar)) {
                System.out.println("Atribuição realizada com sucesso!");
            } else {
                System.out.println("ERRO: Tipos Incompativeis Esperado: " + tokenAtribuicao.getTipoDeclarado() + " Encontrado: " + auxiliar);
                erros.add("ERRO: Tipos Incompativeis Esperado: " + tokenAtribuicao.getTipoDeclarado() + " Encontrado: " + auxiliar);
            }
            System.out.println("String encontrado");
            tokenaux = proximoToken();
        } else if (tokenaux.getTipo().equals("Numero Inteiro") || tokenaux.getTipo().equals("Numero decimal") || tokenaux.getToken().equals("(")) {
            expressaoAritmetica();
        }

    }

    public void incrementoDecremento() {
        if (tokenaux.getToken().equals("++")) {
            System.out.println("Operador Incremento Identificado");
            tokenaux = proximoToken();
        } else if (tokenaux.getToken().equals("--")) {
            System.out.println("Operador Decremento Identificado");
            tokenaux = proximoToken();
        }
    }

    public void condicaoEnquanto() {

        escolha_expressao();

        complementoParaLogica();

        if (tokenaux.getToken().equals(")")) {
            System.out.println("Delimitador ')' encontrado");
            tokenaux = proximoToken();
        }
    }

    public void matriz() {

        if (tokenaux.getToken().equals("[")) {
            System.out.println("Delimitador '[' Identificado");
            tokenaux = proximoToken();

            expressaoAritmetica();

            if (tokenaux.getToken().equals("]")) {
                System.out.println("Delimitador ']' Identificado");
                tokenaux = proximoToken();

            }

        }

    }

    public void senao() {
        if (tokenaux.getToken().equals("senao")) {
            System.out.println("Palavra 'senao' Identificada");
            tokenaux = proximoToken();

            if (tokenaux.getToken().equals("{")) {
                System.out.println("'{' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: '{' não identificado");
            }

            comandos();


            if (tokenaux.getToken().equals("}")) {
                System.out.println("'}' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: '}' não identificado");
            }


        } else {
            System.out.println("Campo 'senao' não declarado");
        }
    }

    public void fatorLeia() {
        if (tokenaux.getTipo().equals("Identificador")) {
            System.out.println("Identificador encontrado");
            tokenaux = proximoToken();
            auxLeia();
        } else {
            System.out.println("Identificador não encontrado Fator Leia não iniciado");
        }

    }

    public void auxLeia() {
        if (tokenaux.getToken().equals(",")) {
            System.out.println("',' Identificado");
            tokenaux = proximoToken();
            fatorLeia();
        } else {
            if (tokenaux.getToken().equals(")")) {
                System.out.println("')' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: ')' e nem ',' não identificados");
            }
        }
    }

    public void fatorEscrita() {

        fatorAux();
        auxEsc();
    }

    public void auxEsc() {

        if (tokenaux.getToken().equals(",")) {
            System.out.println("',' Identificado");
            tokenaux = proximoToken();
            fatorEscrita();
        } else {
            if (tokenaux.getToken().equals(")")) {
                System.out.println("')' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: ',' e ')' não identificados");
            }


        }
    }

    public void fatorAux() {
        if (tokenaux.getToken().equals("cadeia")) {
            System.out.println("'cadeia' Identificado");
            tokenaux = proximoToken();
        } else {
            expressaoAritmetica();
        }
    }

    public void expressaoAritmetica() {
        termoAritm();
        proxTrechoExpAritm();
    }

    public void termoAritm() {
        fator();
        complementoFator();
    }

    public void fator() {

        if (tokenaux.getTipo().equals("Identificador")) {
            System.out.println("Identificador " + tokenaux.getToken() + " encontrado");
            if ((simbolTable.get(tokenaux.getToken()) == null) && (pilhaEscopo.get(0).get(tokenaux.getToken()) == null)) {
                System.out.println("ERRO: Variavel " + tokenaux.getToken() + " não declarada");
                erros.add("ERRO: Variavel " + tokenaux.getToken() + " não declarada");
            } else {
                try {
                    if (tokenAtribuicao.getTipoDeclarado().equals(simbolTable.get(tokenaux.getToken()).getTipoDeclarado())||tokenAtribuicao.getTipoDeclarado().equals((Token)pilhaEscopo.get(0).get(tokenaux.getToken()))) {
                        System.out.println("Fator " + simbolTable.get(tokenaux.getToken()).getToken() + " compatível com " + tokenAtribuicao.getToken());
                    } else {
                        if (tokenAtribuicao.getTipoDeclarado().equals("real")) {
                            if (tokenaux.getTipoDeclarado().equals("inteiro")) {
                                System.out.println("Fator: " + simbolTable.get(tokenaux.getToken()).getToken() + " compatível com " + tokenAtribuicao.getTipoDeclarado());
                            } else {
                                System.out.println("ERRO: fator " + simbolTable.get(tokenaux.getToken()).getToken() + " não compatível com " + tokenAtribuicao.getTipoDeclarado());
                                erros.add("ERRO: fator " + simbolTable.get(tokenaux.getToken()).getToken() + " não compatível com " + tokenAtribuicao.getTipoDeclarado());
                            }
                        } else {
                            System.out.println("ERRO: fator " + simbolTable.get(tokenaux.getToken()).getToken() + " não compatível com " + tokenAtribuicao.getTipoDeclarado());
                            erros.add("ERRO: fator " + simbolTable.get(tokenaux.getToken()).getToken() + " não compatível com " + tokenAtribuicao.getTipoDeclarado());
                        }
                    }
                } catch (NullPointerException e) {
                    Token auxiliar = (Token) pilhaEscopo.get(0).get(tokenaux.getToken());

                    try {
                        if (tokenAtribuicao.getTipoDeclarado().equals(auxiliar.getTipoDeclarado())) {
                            System.out.println("Fator " + auxiliar.getToken() + " compatível com " + tokenAtribuicao.getTipoDeclarado());
                        } else {
                            if (tokenAtribuicao.getTipoDeclarado().equals("real")) {
                                if (auxiliar.getTipoDeclarado().equals("inteiro")) {
                                    System.out.println("Fator: " + auxiliar.getToken() + " compatível com " + tokenAtribuicao.getTipoDeclarado());
                                } else {
                                    System.out.println("ERRO: fator " + auxiliar.getToken() + " não compatível com " + tokenAtribuicao.getTipoDeclarado());
                                    erros.add("ERRO: fator " + auxiliar.getToken() + " não compatível com " + tokenAtribuicao.getTipoDeclarado());
                                }
                            } else {
                                System.out.println("ERRO: fator " + auxiliar.getToken() + " não compatível com " + tokenAtribuicao.getTipoDeclarado());
                                erros.add("ERRO: fator " + auxiliar.getToken() + " não compatível com " + tokenAtribuicao.getTipoDeclarado());
                            }
                        }

                    } catch (NullPointerException t) {
                        System.out.println("ERRO: Expressão não declarada");
                        erros.add("ERRO: Expressão não declarada");
                    }
                }



            }




            tokenaux = proximoToken();
            complementoReferenciaVariado();
        } else {
            if (tokenaux.getTipo().equals("Numero Inteiro") || tokenaux.getTipo().equals("Numero Decimal")) {
                System.out.println("Numero encontrado");
                tokenaux = proximoToken();
            } else if (tokenaux.getToken().equals("(")) {
                System.out.println("'(' encontrado");
                tokenaux = proximoToken();
                expressaoAritmetica();
                if (tokenaux.getToken().equals(")")) {
                    System.out.println("fim da expressao");
                    tokenaux = proximoToken();
                }

            }else if(tokenaux.getTipo().equals("Identificador")){
                System.out.println("Fator atribuido");
            } 
            else if (tokenaux.getToken().equals(")")) {
                System.out.println("')' encontrado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: 'fator' mal formado");

            }
        }
    }

    public void complementoFator() {
        if (tokenaux.getToken().equals("*") || tokenaux.getTipo().equals("OPERADOR DE DIVISÃO")) {
            operadorMultiplicacao();
            termoAritm();

        } else {
            System.out.println("Sem complemento fator");
        }

    }

    public void complementoReferenciaVariado() {
        if (tokenaux.getToken().equals("[")) {
            System.out.println("'[' Identificado");
            tokenaux = proximoToken();

            expressaoAritmetica();

            if (tokenaux.getToken().equals("]")) {
                System.out.println("']' Identificado");
                tokenaux = proximoToken();
            } else {
                System.out.println("ERRO: ']' não Identificado");
            }
            matriz();

        } else {
            System.out.println("'[' não Identificado");
            if (tokenaux.getToken().equals(".")) {
                System.out.println("'.' Identificado");
                tokenaux = proximoToken();

                if (tokenaux.getTipo().equals("Identificador")) {
                    if (simbolTable.get(tokenaux.getToken()) == null && pilhaEscopo.get(0).get(tokenaux.getToken()) == null) {
                        System.out.println("ERRO: Variavel " + tokenaux.getToken() + " não declarada");
                        erros.add("ERRO: Variavel " + tokenaux.getToken() + " não declarada");
                    }
                    if (tokenAtribuicao.getTipo().equals("inteiro")) {
                        try {
                            if (simbolTable.get(tokenaux.getToken()).getTipoDeclarado().equals("real")) {
                                System.out.println("ERRO: Tipo esperado em " + tokenAtribuicao.getToken() + " = " + tokenAtribuicao.getTipoDeclarado() + " Encontrado: real");
                                erros.add("ERRO: Tipo esperado em " + tokenAtribuicao.getToken() + " = " + tokenAtribuicao.getTipoDeclarado() + " Encontrado: real");
                            }
                            if (simbolTable.get(tokenaux.getToken()).getTipoDeclarado().equals("cadeia")) {
                                System.out.println("ERRO: Tipo esperado em " + tokenAtribuicao.getToken() + " = " + tokenAtribuicao.getTipoDeclarado() + " Encontrado: cadeia");
                                erros.add("ERRO: Tipo esperado em " + tokenAtribuicao.getToken() + " = " + tokenAtribuicao.getTipoDeclarado() + " Encontrado: cadeia");
                            }
                            if (simbolTable.get(tokenaux.getToken()).getTipoDeclarado().equals("caractere")) {
                                System.out.println("ERRO: Tipo esperado em " + tokenAtribuicao.getToken() + " = " + tokenAtribuicao.getTipoDeclarado() + " Encontrado: caractere");
                                erros.add("ERRO: Tipo esperado em " + tokenAtribuicao.getToken() + " = " + tokenAtribuicao.getTipoDeclarado() + " Encontrado: caractere");
                            }
                        } catch (NullPointerException e) {
                        }
                    } else if (tokenAtribuicao.getTipo().equals("real")) {
                        try {
                            if (simbolTable.get(tokenaux.getToken()).getTipoDeclarado().equals("cadeia")) {
                                System.out.println("ERRO: Tipo esperado em " + tokenAtribuicao.getToken() + " = " + tokenAtribuicao.getTipoDeclarado() + " Encontrado: cadeia");
                                erros.add("ERRO: Tipo esperado em " + tokenAtribuicao.getToken() + " = " + tokenAtribuicao.getTipoDeclarado() + " Encontrado: cadeia");
                            }
                            if (simbolTable.get(tokenaux.getToken()).getTipoDeclarado().equals("caractere")) {
                                System.out.println("ERRO: Tipo esperado em " + tokenAtribuicao.getToken() + " = " + tokenAtribuicao.getTipoDeclarado() + " Encontrado: caractere");
                                erros.add("ERRO: Tipo esperado em " + tokenAtribuicao.getToken() + " = " + tokenAtribuicao.getTipoDeclarado() + " Encontrado: caractere");
                            }
                        } catch (NullPointerException e) {
                        }
                    }
                    System.out.println("'Identificador' Identificado");
                    tokenaux = proximoToken();
                } else {
                    System.out.println("ERRO: 'Identificador' não Encontrado");
                }

            } else {
                System.out.println("'.' não Identificado");
            }

        }
    }

    public void operadorMultiplicacao() {
        if (tokenaux.getToken().equals("*")) {
            System.out.println("Operador '*' encontrado");
            tokenaux = proximoToken();
        } else if (tokenaux.getTipo().equals("OPERADOR DE DIVISÃO")) {
            System.out.println("Operador '/' encontrado");
            tokenaux = proximoToken();
        } else {
            System.out.println("ERROR: Operador '*' e nem operador '/' encontrados");
        }
    }

    public void proxTrechoExpAritm() {

        if (tokenaux.getToken().equals("+") || tokenaux.getToken().equals("-")) {
            operadorSoma();
            expressaoAritmetica();
        } else {
            System.out.println("Operador soma/subtração não identificado");
        }
    }

    public void operadorSoma() {
        if (tokenaux.getToken().equals("+")) {
            System.out.println("Operador + encontrado");
            tokenaux = proximoToken();
        } else if (tokenaux.getToken().equals("-")) {
            System.out.println("Operador - Encontrado");
            tokenaux = proximoToken();
        }
    }

    public void retorno() {
        if (tokenaux.getToken().equals("retorno")) {
            System.out.println("'retorno' Encontrado");
            tokenaux = proximoToken();
        } else {
            System.out.println("ERRO: retorno não encontrado");
        }

        valor();

        if (tokenaux.getToken().equals(";")) {
            System.out.println("Palavra ';' identificada");
            tokenaux = proximoToken();
        } else {
            System.out.println("ERROR: Esperado o ';'");
        }

    }

    public void valor() {
        Token aux = tokenaux;
        if (tokenaux.getToken().equals("vazio") || tokenaux.getTipo().equals("Identificador")) {
            System.out.println("valor identificado corretamente");
            if (tokenaux.getTipo().equals("Identificador")) {
                if (simbolTable.get(tokenaux.getToken()) == null) {
                    System.out.println("ERRO: Variavel " + tokenaux.getToken() + " retornada não declarada neste escopo");
                    erros.add("ERRO: Variavel " + tokenaux.getToken() + " retornada não declarada neste escopo");
                }


                if (pilhaEscopo.get(0).get(tokenaux.getToken()) != null) {
                    aux = (Token) pilhaEscopo.get(0).get(tokenaux.getToken());
                    if (tokenFuncao.getTipoDeclarado().equals(aux.getTipoDeclarado())) {
                        System.out.println("Tipo de função compatível com o tipo do Retorno");
                    } else {
                        System.out.println("ERRO: Tipo de função Incompatível com o tipo do Retorno");
                        erros.add("ERRO: Tipo de função Incompatível com o tipo do Retorno");
                    }
                } else if (simbolTable.get(tokenaux.getToken()) != null) {
                    aux = simbolTable.get(tokenaux.getToken());
                    if (tokenFuncao.getTipoDeclarado().equals(aux.getTipoDeclarado())) {
                        System.out.println("Tipo de função compatível com o tipo do Retorno");
                    } else {
                        System.out.println("ERRO: Tipo de função Incompatível com o tipo do Retorno");
                        erros.add("ERRO: Tipo de função Incompatível com o tipo do Retorno");
                    }
                }
                System.out.println(tokenFuncao.getTipoDeclarado());
                System.out.println(aux.getTipoDeclarado());



            } else if (tokenaux.getToken().equals("vazio")) {
                if (!tokenaux.getToken().equals("vazio")) {
                    System.out.println("ERRO: Variavel " + tokenaux.getToken() + " retornada não declarada neste escopo");
                    erros.add("ERRO: Variavel " + tokenaux.getToken() + " retornada não declarada neste escopo");
                }


                if (tokenaux.getToken() != null) {

                    if (tokenFuncao.getTipoDeclarado().equals(tokenaux.getToken())) {
                        System.out.println("Tipo de função compatível com o tipo do Retorno");
                    } else {
                        System.out.println("ERRO: Tipo de função Incompatível com o tipo do Retorno");
                        erros.add("ERRO: Tipo de função Incompatível com o tipo do Retorno");
                    }
                }
            }
            tokenaux = proximoToken();

        } else {
            System.out.println("ERRO: Valor de retorno inválido!");
            erros.add("ERRO: Valor de retorno inválido!");
        }
    }

    public void funcaoCorpoPrincipal() {
        if (tokenaux.getToken().equals("{")) {
            System.out.println("'{' Encontrado");
            tokenaux = proximoToken();
        } else {
            System.out.println("ERRO: { não encontrado");
        }
        if (tokenaux.getToken().equals("variaveis")) {
            indiceEscopo++;
            pilhaEscopo.add(new Hashtable<String, Token>());
            simbolTable = pilhaEscopo.get(indiceEscopo);
        }
        variaveis(tokenaux);
        comandos();

        if (tokenaux.getToken().equals("retorno")) {
            System.out.println("'retorno' Encontrado");
            tokenaux = proximoToken();
        } else {
            System.out.println("ERRO: retorno não encontrado");
        }

        if (tokenaux.getToken().equals("vazio")) {
            System.out.println("'vazio' Encontrado");
            tokenaux = proximoToken();
        } else {
            System.out.println("ERRO: vazio não encontrado");
        }

        if (tokenaux.getToken().equals(";")) {
            System.out.println("Palavra ';' identificada");
            tokenaux = proximoToken();
        } else {
            System.out.println("ERROR: Esperado o ';'");
        }

        if (tokenaux.getToken().equals("}")) {
            System.out.println("'}' Encontrado");
            tokenaux = proximoToken();
        } else {
            System.out.println("ERRO: } não encontrado");
        }
    }

    public void renomearTipo() {

        if (tokenaux.getToken().equals("tipo") || noidentificador == 1) {


            System.out.println("Bloco de tipo declarado");
            tokenaux = proximoToken();
            tipo(tokenaux);

            if (tokenaux.getTipo().equals("Identificador")) {

                System.out.println("Identificador encontrado");
                tokenaux = proximoToken();

                if (tokenaux.getToken().equals(";")) {
                    System.out.println("; encontrado");
                    tokenaux = proximoToken();

                }
                renomearTipo();
            }
        } else {
            System.out.println("Bloco de tipo não declarado");
            while (!tokenaux.getToken().equals("funcao") && !tokenaux.getToken().equals("principal")) {
                tokenaux = proximoToken();
            }
        }
    }

    public void registro() {
        if (tokenaux.getToken().equals("registro")) {

            System.out.println("registro encontrado");
            tokenaux = proximoToken();


            if (tokenaux.getTipo().equals("Identificador")) {


                System.out.println("Identificador " + tokenaux.getToken() + " encontrado");
                if (pilhaEscopo.get(0).get(tokenaux.getToken()) == null) {
                    pilhaEscopo.get(0).put(tokenaux.getToken(), tokenaux);
                } else {
                    System.out.println("ERRO: Registro " + tokenaux.getToken() + " já declarado");
                    erros.add("ERRO: Registro " + tokenaux.getToken() + " já declarado");
                }
                tokenaux = proximoToken();



                if (tokenaux.getToken().equals("{")) {

                    System.out.println("{ encontrado");
                    tokenaux = proximoToken();


                    declaracaoRegistro();

                    registro();

                }



            }



        } else {
            System.out.println("Novo Bloco de registro não declarado");
            while (!tokenaux.getToken().equals("tipo") && !tokenaux.getToken().equals("funcao") && !tokenaux.getToken().equals("principal")) {
                tokenaux = proximoToken();
            }
        }
    }

    public void declaracaoRegistro() {

        tipo(tokenaux);

        if (tokenaux.getTipo().equals("Identificador")) {

            System.out.println("identificador " + tokenaux.getToken() + " encontrado");
            tokenaux = proximoToken();

            if (tokenaux.getToken().equals(";")) {

                System.out.println("; encontrado");
                tokenaux = proximoToken();


                declaracaoRegistroVariaveis();


            }



        } else {
            declaracaoRegistroVariaveis();
        }

    }

    public void declaracaoRegistroVariaveis() {

        Token tokenteste;
        tokenteste = tokenaux;


        tipo(tokenaux);


        if (tokenteste.equals(tokenaux)) {


            if (tokenaux.getToken().equals("}")) {

                System.out.println("} encontrado");
                tokenaux = proximoToken();

                if (tokenaux.getToken().equals(";")) {
                    System.out.println("; encontrado");
                    System.out.println("Fim do Bloco de Registro");
                    tokenaux = proximoToken();
                }
            }
        } else {
            indiceToken--;
            tokenaux = tokenteste;
            declaracaoRegistro();
        }
    }

    public void declaracaoConstantesMesmoTipo(Token token) {

        tokenaux = token;
        if (tokenaux.getToken().equals(",")) {
            tokenaux = proximoToken();
            if (tokenaux.getTipo().equals("Identificador")) {
                if ((simbolTable.get(tokenaux.getToken()) != null) && (!simbolTable.isEmpty())) {
                    System.out.println("ERRO: Identificador " + tokenaux.getToken() + " já declarado neste escopo!");
                    erros.add("ERRO: Identificador " + tokenaux.getToken() + " já declarado neste escopo!");
                } else {
                    simbolTable.put(tokenaux.getToken(), tokenaux);
                }
                tokenaux = proximoToken();
                if (tokenaux.getToken().equals("=")) {
                    tokenaux = proximoToken();
                    valorConstante(tokenaux);
                    declaracaoConstantesMesmoTipo(tokenaux);
                } else {
                    System.out.println("Operador '=' não encontrado.");
                    while (!tokenaux.getToken().equals(",") && !tokenaux.getToken().equals(";")
                            && !tokenaux.getToken().equals("}") && !tokenaux.getTipo().equals("Identificador")) {
                        tokenaux = proximoToken();
                    }
                    if (tokenaux.getToken().equals(",")) {
                        declaracaoConstantesMesmoTipo(tokenaux);
                    } else if (tokenaux.getToken().equals(";")) {
                        tokenaux = proximoToken();
                        declaracaoConstantes(tokenaux);
                    } else if (tokenaux.getToken().equals("}")) {
                        declaracaoConstantes(tokenaux);
                    } else if (tokenaux.getTipo().equals("Identificador") || tokenaux.getToken().equals("Palavra Reservada")) {
                        System.out.println("Erro ';' esperado e não encontrado");
                        declaracaoConstantes(tokenaux);
                    }

                }
            } else {
                System.out.println("ERRO: Identificador não encontrado");
                while (!tokenaux.getToken().equals(",") && !tokenaux.getToken().equals(";") && !tokenaux.getToken().equals("}")
                        && !tokenaux.getTipo().equals("Identificador")) {
                    tokenaux = proximoToken();
                }
                if (tokenaux.getToken().equals(",")) {
                    declaracaoConstantesMesmoTipo(tokenaux);
                } else if (tokenaux.getToken().equals(";")) {
                    tokenaux = proximoToken();
                    declaracaoConstantes(tokenaux);
                } else if (tokenaux.getToken().equals("}")) {
                    declaracaoConstantes(tokenaux);
                } else if (tokenaux.getTipo().equals("Identificador")) {
                    if (tokenaux.getTipo().equals("Identificador")) {
                        tokenaux = proximoToken();
                        if (tokenaux.getToken().equals("=")) {
                            tokenaux = proximoToken();
                            valorConstante(tokenaux);
                            declaracaoConstantesMesmoTipo(tokenaux);
                        }
                    }
                }

            }
        } else if (tokenaux.getToken().equals(";")) {
            tokenaux = proximoToken();
            declaracaoConstantes(tokenaux);
        } else if (tokenaux.getToken().equals(";")) {
            tokenaux = proximoToken();
            declaracaoConstantes(tokenaux);
        } else if (tokenaux.getTipo().equals("Identificador") || tokenaux.getTipo().equals("Palavra Reservada")) {
            System.out.println("ERRO: ';' não encontrado");
            declaracaoConstantes(tokenaux);

        }


    }

    public void valorConstante(Token token) {

        tokenaux = token;
        String tipo = null;
        if (tokenaux.getTipo().equals("cadeia") || tokenaux.getTipo().equals("CARACTERE BEM FORMADO") || tokenaux.getTipo().equals("Numero decimal") || tokenaux.getTipo().equals("Numero Inteiro") || tokenaux.getTipo().equals("Numero Real")
                || tokenaux.getTipo().equals("caractere") || tokenaux.getTipo().equals("logico") || tokenaux.getTipo().equals("String") || tokenaux.getTipo().equals("Identificador") || tokenaux.getToken().equals("verdadeiro") || tokenaux.getToken().equals("falso")) {
            System.out.println("Valor: " + tokenaux.getToken() + " atribuido!!");

            tipo = tokenaux.getTipo();

            if (tokenaux.getTipo().equals("CARACTERE BEM FORMADO")) {
                tipo = "caractere";
            } else if (tokenaux.getTipo().equals("String")) {
                tipo = "cadeia";
            } else if (tokenaux.getTipo().equals("Numero decimal")) {
                tipo = "real";
            } else if (tokenaux.getTipo().equals("Numero Inteiro")) {
                tipo = "inteiro";
            } else if (tokenaux.getToken().equals("verdadeiro") || tokenaux.getToken().equals("falso")) {
                tipo = "logico";
            }


            //    System.out.println(listadeTokens.get(indiceToken-4).getToken());

            if (tipo.equals(listadeTokens.get(indiceToken - 4).getToken())) {
                System.out.println("Atribuição feita com Tipos Compatíveis!");
            } else if(listadeTokens.get(indiceToken - 4).getToken().equals("real") && tipo.equals("inteiro")){

                  System.out.println("Atribuição feita com Tipos Compatíveis!");
            } else {
                System.out.println("ERRO: Atribuição feita com Tipos não compatíveis! Esperado: " + listadeTokens.get(indiceToken - 4).getToken() + "," + " Encontrado: " + tipo);
                erros.add("ERRO: Atribuição feita com Tipos não compatíveis! Esperado: " + listadeTokens.get(indiceToken - 4).getToken() + "," + " Encontrado: " + tipo);
            }

            tokenaux = proximoToken();
        } else {
            System.out.println("ERRO Valor inesperado");
        }

    }

    public void declaracaoConstantes(Token token) {

        tokenaux = token;

        if (tokenaux.getToken().equals("}")) {
            System.out.println("Fim do bloco de constantes declarado");
            tokenaux = proximoToken();
        } else if (tokenaux.getTipo().equals("Palavra Reservada") || tokenaux.getTipo().equals("Identificador")) {
            // System.out.println("Cu");
            tipoConstante(tokenaux);
            if (tokenaux.getTipo().equals("Identificador")) {
                System.out.println("Identificador: " + tokenaux.getToken() + "Tipo Declarado: " + tokenaux.getTipoDeclarado());
                if ((simbolTable.get(tokenaux.getToken()) != null) && (!simbolTable.isEmpty())) {
                    System.out.println("ERRO: Identificador " + tokenaux.getToken() + " já declarado neste escopo!");
                    erros.add("ERRO: Identificador " + tokenaux.getToken() + " já declarado neste escopo!");
                } else {
                    simbolTable.put(tokenaux.getToken(), tokenaux);
                }
                tokenaux = proximoToken();
                if (tokenaux.getToken().equals("=")) {
                    tokenaux = proximoToken();
                    valorConstante(tokenaux);
                    declaracaoConstantesMesmoTipo(tokenaux);
                } else {
                    System.out.println("Operador '=' não encontrado.");
                    while (!tokenaux.getToken().equals(",") && !tokenaux.getToken().equals(";")
                            && !tokenaux.getToken().equals("}")) {
                        tokenaux = proximoToken();
                    }
                    if (tokenaux.getToken().equals(",")) {
                        declaracaoConstantesMesmoTipo(tokenaux);
                    } else if (tokenaux.getToken().equals(";")) {
                        tokenaux = proximoToken();
                        declaracaoConstantes(tokenaux);
                    } else if (tokenaux.getToken().equals("}")) {
                        declaracaoConstantes(tokenaux);
                    }

                }
            } else {
                System.out.println("Identificador não em contrado.");
                while (!tokenaux.getToken().equals("}") && !tokenaux.getToken().equals(",") && !tokenaux.getToken().equals(";")
                        && !tokenaux.getTipo().equals("Identificador")) {
                    tokenaux = proximoToken();
                }
                if (tokenaux.getTipo().equals("Identificador")) { //to aki
                    tokenaux = proximoToken();
                    if (tokenaux.getToken().equals("=")) {
                        tokenaux = proximoToken();
                        valorConstante(tokenaux);
                        declaracaoConstantesMesmoTipo(tokenaux);
                    }
                } else if (tokenaux.getToken().equals("}")) {
                    System.out.println("Nenhuma constante declarada! em " + tokenaux.getToken());
                    declaracaoConstantes(tokenaux);
                } else if (tokenaux.getToken().equals(",")) {
                    declaracaoConstantesMesmoTipo(tokenaux);
                } else if (tokenaux.getToken().equals(";")) {
                    declaracaoConstantesMesmoTipo(tokenaux);
                }
            }

        } else {
            System.out.println("Tipo de constante não encontrado");
            while (!tokenaux.getTipo().equals("Palavra Reservada") && !tokenaux.getTipo().equals("Identificador") && !tokenaux.getTipo().equals("}")) {
                tokenaux = proximoToken();
            }
            if (tokenaux.getTipo().equals("Palavra Reservada") || tokenaux.getTipo().equals("Identificador")) {
                if (tokenaux.getTipo().equals("Identificador")) {
                    tokenaux = proximoToken();
                    if (tokenaux.getToken().equals("=")) {
                        tokenaux = proximoToken();
                        valorConstante(tokenaux);
                        declaracaoConstantesMesmoTipo(tokenaux);
                    }
                }
            } else if (tokenaux.getToken().equals("}")) {
                System.out.println("Fim do bloco de constantes declarado");
                tokenaux = proximoToken();
            }
        }

    }

    public void tipoConstante(Token token) {
        //System.out.println("Entrou no tipo!!!!!" + token.getToken());
        if (token.getToken().equals("inteiro") || token.getToken().equals("real") || token.getToken().equals("cadeia")
                || token.getToken().equals("caractere") || token.getTipo().equals("Identificador") || token.getToken().equals("logico")) {

            System.out.println("Tipo Identificado");
            tokenaux = proximoToken();
            tokenaux.setTipoDeclarado(token.getToken());
        } else {
            System.out.println("Tipo não encontrado!");
            while (!token.getToken().equals("inteiro") && !token.getToken().equals("real") && !token.getToken().equals("cadeia")
                    && !token.getToken().equals("caractere") && !token.getTipo().equals("Identificador") && !token.getToken().equals("logico")
                    && token.getToken().equals("}")) {
                tokenaux = proximoToken();
            }
            if (tokenaux.getToken().equals("}")) {
                declaracaoConstantes(tokenaux);
            } else if (tokenaux.getToken().equals("inteiro") || tokenaux.getToken().equals("real") || tokenaux.getToken().equals("cadeia")
                    || tokenaux.getToken().equals("caractere") || tokenaux.getTipo().equals("Identificador") || tokenaux.getToken().equals("logico")) {
                declaracaoConstantes(tokenaux);
            }
        }


    }

    public void tipo(Token token) {

        if (token.getToken().equals("inteiro") || token.getToken().equals("real") || token.getToken().equals("cadeia")
                || token.getToken().equals("caractere") || token.getTipo().equals("Identificador") || token.getToken().equals("logico")) {

            System.out.println("Tipo: " + token.getToken() + " identificado");
            tokenaux = proximoToken();
            tokenaux.setTipoDeclarado(token.getToken());
        } else {
            System.out.println("Tipo não encontrado!");
        }

    }

    public void tipoFuncao(Token token) {
        // System.out.println("Entrou no tipo_funcao!!!!!" + token.getToken());
        if (token.getToken().equals("inteiro") || token.getToken().equals("real") || token.getToken().equals("cadeia")
                || token.getToken().equals("caractere") || token.getTipo().equals("Identificador") || token.getToken().equals("logico") || token.getToken().equals("vazio")) {

            System.out.println("Tipo_Função " + tokenaux.getToken() + " Identificado");
            tokenaux = proximoToken();
            tokenaux.setTipoDeclarado(token.getToken());

        } else {
            System.out.println("Tipo_Função não encontrado!");
        }

    }

    public void constantes(Token token) {
        tokenaux = token;

        if (tokenaux.getToken().equals("constantes")) {
            tokenaux = proximoToken();
            if (tokenaux.getToken().equals("{")) {
                pilhaEscopo.add(new Hashtable<String, Token>());
                indiceEscopo++;
                simbolTable = pilhaEscopo.get(indiceEscopo);
                tokenaux = proximoToken();
                declaracaoConstantes(tokenaux); //terminar a implementação de reconhecimento de constantes
            } else {
                System.out.println("{ Faltando em constantes");
                declaracaoConstantes(tokenaux);
            }
        } else {
            System.out.println("Bloco de constantes não declarado");
            while (!tokenaux.getToken().equals("variaveis") && !tokenaux.getToken().equals("registro") && !tokenaux.getToken().equals("tipo")
                    && !tokenaux.getToken().equals("funcao") && !tokenaux.getToken().equals("principal")) {
                tokenaux = proximoToken();
            }
            if (tokenaux.getToken().equals("variaveis")) {
                System.out.println("encontrou variáveis");
            } else if (tokenaux.getToken().equals("registro")) {
                System.out.println("encontrou registro");
            }
        }

    }

    public void variaveis(Token token) { //ok
        tokenaux = token;

        if (tokenaux.getToken().equals("variaveis")) {
            System.out.println("Entrou no bloco Variaveis");
            tokenaux = proximoToken();
            if (tokenaux.getToken().equals("{")) {
                System.out.println("{ encontrado");
                tokenaux = proximoToken();
                declaracaoVariaveis(tokenaux);
            } else {
                System.out.println("{ Faltando em variaveis");
                declaracaoVariaveis(tokenaux);
            }
        } else {
            System.out.println("Bloco de variaveis não declarado");

        }


    }

    public void declaracaoVariaveis(Token token) { //ok
        tokenaux = token;

        if (tokenaux.getTipo().equals("Palavra Reservada") || tokenaux.getTipo().equals("Identificador")) {
            tipo(tokenaux);
            //  tokenaux = proximoToken();
            if (tokenaux.getTipo().equals("Identificador")) {
                System.out.println("Identificador: " + tokenaux.getToken() + " encontrado.");
                if ((simbolTable.get(tokenaux.getToken()) != null) && (!simbolTable.isEmpty())) {
                    System.out.println("ERRO: Identificador " + tokenaux.getToken() + " já declarado neste escopo!");
                    erros.add("ERRO: Identificador " + tokenaux.getToken() + " já declarado neste escopo!");
                } else {
                    simbolTable.put(tokenaux.getToken(), tokenaux);
                }
                tokenaux = proximoToken();
                declaraVariavelouArray(tokenaux);

            } else {
                System.out.println("Identificador nao encontrado!");

            }

        } else if (tokenaux.getToken().equals("}")) {
            tokenaux = proximoToken();
            System.out.println("Fim do bloco de Variaveis.");
        }



    }

    public void declaraVariavelouArray(Token token) { //ok
        tokenaux = token;
        if (tokenaux.getToken().equals("=")) {
            inicializaVariavel(tokenaux);
        } else if (tokenaux.getToken().equals("[")) {
            array(tokenaux);
        } else {
            System.out.println("Operador '=' não encontrado, ou '[' faltando na declaração do vetor");

            if (tokenaux.getToken().equals(",")) {
                declaracaoVariavelMesmoTipo(token);
            }
        }


    }

    public void inicializaVariavel(Token token) { //ok
        tokenaux = token;
        if (tokenaux.getToken().equals("=")) {
            System.out.println("Operador = reconhecido.");
            tokenaux = proximoToken();
            valorVariavel(tokenaux);
            declaracaoVariavelMesmoTipo(token);
        } else if (tokenaux.getToken().equals(",")) {
            declaracaoVariavelMesmoTipo(tokenaux);
        } else if (tokenaux.getToken().equals(";")) {
            declaracaoVariavelMesmoTipo(tokenaux);
        } else {
            System.out.println("ERRO: operador '=' faltando, ou ',' não presente em " + tokenaux.getToken());
            erros.add("ERRO: operador '=' faltando, ou ',' não presente em " + tokenaux.getToken());
        }
    }

    public void declaracaoVariavelMesmoTipo(Token token) { //ok

        if (tokenaux.getToken().equals(",")) {
            System.out.println(", encontrada");
            tokenaux = proximoToken();
            if (tokenaux.getTipo().equals("Identificador")) {
                System.out.println("Identificador: " + tokenaux.getToken() + " encontrado.");
                if ((simbolTable.get(tokenaux.getToken()) != null) && (!simbolTable.isEmpty())) {
                    System.out.println("ERRO: Identificador " + tokenaux.getToken() + " já declarado neste escopo!");
                    erros.add("ERRO: Identificador " + tokenaux.getToken() + " já declarado neste escopo!");
                } else {
                    simbolTable.put(tokenaux.getToken(), tokenaux);
                }
                tokenaux = proximoToken();
                inicializaVariavel(tokenaux);
            }
        } else if (tokenaux.getToken().equals(";")) {
            System.out.println("Fim da declaração de variavel - ; encontrado");
            tokenaux = proximoToken();
            declaracaoVariaveis(tokenaux);
        }

    }

    public void array(Token token) { //ok
        tokenaux = token;

        if (tokenaux.getToken().equals("[")) {
            System.out.println("Delimitador [ encontrado");
            tokenaux = proximoToken();
            if (tokenaux.getTipo().equals("Numero Inteiro")) {
                System.out.println("tamanho do vetor = " + tokenaux.getToken());
                tokenaux = proximoToken();
                if (tokenaux.getToken().equals("]")) {
                    System.out.println("Delimitador ] encontrado");
                    System.out.println("Declaração do vetor realizada com sucesso.");
                    tokenaux = proximoToken();
                    declaracaoVetorouMatriz(tokenaux);
                }
            } else {
                System.out.println("ERRO: Valor da dimensão do vetor não é um Numero Inteiro");
                erros.add("ERRO: Valor da dimensão do vetor não é um Numero Inteiro");
                tokenaux = proximoToken();
                if (tokenaux.getToken().equals("]")) {
                    System.out.println("Delimitador ] encontrado");
                    //    System.out.println("Declaração do vetor realizada com sucesso.");
                    tokenaux = proximoToken();
                    declaracaoVetorouMatriz(tokenaux);
                }
            }
        }
    }

    public void valorVariavel(Token token) { //ok
        tokenaux = token;
        String tipo = null;
        if (tokenaux.getTipo().equals("cadeia") || tokenaux.getTipo().equals("CARACTERE BEM FORMADO") || tokenaux.getTipo().equals("Numero decimal") || tokenaux.getTipo().equals("Numero Inteiro") || tokenaux.getTipo().equals("Numero Real")
                || tokenaux.getTipo().equals("caractere") || tokenaux.getTipo().equals("logico") || tokenaux.getTipo().equals("String") || tokenaux.getTipo().equals("Identificador") || tokenaux.getToken().equals("verdadeiro") || tokenaux.getToken().equals("falso")) {
            System.out.println("Valor: " + tokenaux.getToken() + " atribuido!!");

            tipo = tokenaux.getTipo();

            if (tokenaux.getTipo().equals("CARACTERE BEM FORMADO")) {
                tipo = "caractere";
            } else if (tokenaux.getTipo().equals("String")) {
                tipo = "cadeia";
            } else if (tokenaux.getTipo().equals("Numero decimal")) {
                tipo = "real";
            } else if (tokenaux.getTipo().equals("Numero Inteiro")) {
                tipo = "inteiro";
            } else if (tokenaux.getToken().equals("verdadeiro") || tokenaux.getToken().equals("falso")) {
                tipo = "logico";
            }


            //    System.out.println(listadeTokens.get(indiceToken-4).getToken());

            if (tipo.equals(listadeTokens.get(indiceToken - 4).getToken())) {
                System.out.println("Atribuição feita com Tipos Compatíveis!");
            } else if(listadeTokens.get(indiceToken - 4).getToken().equals("real") && tipo.equals("inteiro")){

                  System.out.println("Atribuição feita com Tipos Compatíveis!");
            } else {
                System.out.println("ERRO: Atribuição feita com Tipos não compatíveis! Esperado: " + listadeTokens.get(indiceToken - 4).getToken() + "," + " Encontrado: " + tipo);
                erros.add("ERRO: Atribuição feita com Tipos não compatíveis! Esperado: " + listadeTokens.get(indiceToken - 4).getToken() + "," + " Encontrado: " + tipo);
            }

            tokenaux = proximoToken();
        } else {
            System.out.println("Valor não encontrado!");
        }
    }

    public void declaracaoVetorouMatriz(Token token) { //ok
        tokenaux = token;
        if (tokenaux.getToken().equals("[")) {
            tokenaux = proximoToken();
            if (tokenaux.getTipo().equals("Numero Inteiro")) {
                tokenaux = proximoToken();
                if (tokenaux.getToken().equals("]")) {
                    System.out.println("Matriz declarada com sucesso!");
                    tokenaux = proximoToken();
                    declaracaoMatrizMesmoTipo(tokenaux);
                }
            } else {
                System.out.println("ERRO: Valor da dimensão do vetor não é um Numero Inteiro");
                erros.add("ERRO: Valor da dimensão do vetor não é um Numero Inteiro");
                tokenaux = proximoToken();
                if (tokenaux.getToken().equals("]")) {
                    // System.out.println("Matriz declarada com sucesso!");
                    tokenaux = proximoToken();
                    declaracaoMatrizMesmoTipo(tokenaux);
                }
            }
        } else if (tokenaux.getToken().equals(",")) {
            declaraVetorMesmoTipo(tokenaux);
        } else if (tokenaux.getToken().equals(";")) {
            tokenaux = proximoToken();
            declaracaoVariaveis(tokenaux);
        }
    }

    public void declaracaoMatrizMesmoTipo(Token token) { //ok
        tokenaux = token;
        if (tokenaux.getToken().equals(",")) {
            tokenaux = proximoToken();
            if (tokenaux.getTipo().equals("Identificador")) {
                System.out.println("Identificador " + tokenaux.getToken() + " da matriz encontrado");
                if ((simbolTable.get(tokenaux.getToken()) != null) && (!simbolTable.isEmpty())) {
                    System.out.println("ERRO: Identificador " + tokenaux.getToken() + " já declarado neste escopo!");
                    erros.add("ERRO: Identificador " + tokenaux.getToken() + " já declarado neste escopo!");
                } else {
                    simbolTable.put(tokenaux.getToken(), tokenaux);
                }
                tokenaux = proximoToken();
                if (tokenaux.getToken().equals("[")) {
                    System.out.println("Delimitador [ encontrado");
                    tokenaux = proximoToken();
                    if (tokenaux.getTipo().equals("Numero Inteiro")) {
                        System.out.println("Dimensão da linha= " + tokenaux.getToken() + " encontrado");
                        tokenaux = proximoToken();
                        if (tokenaux.getToken().equals("]")) {
                            System.out.println("Delimitador ] encontrado");
                            tokenaux = proximoToken();
                            if (tokenaux.getToken().equals("[")) {
                                System.out.println("Segundo Delimitador [ encontrado");
                                tokenaux = proximoToken();
                                if (tokenaux.getTipo().equals("Numero Inteiro")) {
                                    System.out.println("Dimensão da coluna= " + tokenaux.getToken() + " encontrada");
                                    tokenaux = proximoToken();
                                    if (tokenaux.getToken().equals("]")) {
                                        System.out.println("Segundo Delimitador ] encontrado");
                                        tokenaux = proximoToken();
                                        System.out.println("Matriz declarada com sucesso.");
                                        declaracaoMatrizMesmoTipo(tokenaux);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } else if (tokenaux.getToken().equals(";")) {
            System.out.println("Fim da declaração Matriz!");
            tokenaux = proximoToken();
            declaracaoVariaveis(tokenaux);
        }

    }

    public void declaraVetorMesmoTipo(Token token) { //ok
        tokenaux = token;
        if (tokenaux.getToken().equals(",")) {
            tokenaux = proximoToken();
            if (tokenaux.getTipo().equals("Identificador")) {
                System.out.println("Identificador " + tokenaux.getToken() + " reconhecido");
                if ((simbolTable.get(tokenaux.getToken()) != null) && (!simbolTable.isEmpty())) {
                    System.out.println("ERRO: Identificador " + tokenaux.getToken() + " já declarado neste escopo!");
                    erros.add("ERRO: Identificador " + tokenaux.getToken() + " já declarado neste escopo!");
                } else {
                    simbolTable.put(tokenaux.getToken(), tokenaux);
                }
                tokenaux = proximoToken();
                if (tokenaux.getToken().equals("[")) {
                    System.out.println("Delimitador [ encontrado");
                    tokenaux = proximoToken();
                    if (tokenaux.getTipo().equals("Numero Inteiro")) {
                        System.out.println("tamanho do vetor = " + tokenaux.getToken());
                        tokenaux = proximoToken();
                        if (tokenaux.getToken().equals("]")) {
                            System.out.println("Delimitador ] encontrado");
                            tokenaux = proximoToken();
                            System.out.println("Vetor declarado com sucesso.");
                            declaraVetorMesmoTipo(tokenaux);
                        }
                    }
                }
            }
        } else if (tokenaux.getToken().equals(";")) {
            System.out.println("Fim da declaração de vetores do mesmo tipo");
            tokenaux = proximoToken();
            declaracaoVariaveis(tokenaux);
        }

    }

    public void inicio(Token token) {

        System.out.println("entrou");
        if (token.getToken().equals("programa")) {
            System.out.println("programa econtrado");
            tokenaux = proximoToken();

            if (tokenaux.getTipo().equals("Identificador")) {

                System.out.println("identificador encontrado");
                tokenaux = proximoToken();

                if (tokenaux.getToken().equals(";")) {
                    System.out.println("';' encontrado");
                    estrutura(proximoToken());
                }
            }
        }


    }

    public void analyseListTokens() {

        inicio(proximoToken());
        if (tokenaux.getToken().equals("$")) {
            System.out.println("SUCESSO");
            // System.exit(0);
        } else if (proximoToken().getToken().equals("$")) {
            System.out.println("SUCESSO");
            // System.exit(0);
        }

    }

    public Token proximoToken() {
        if (listadeTokens.size() > indiceToken) {
            Token token = listadeTokens.get(indiceToken);
            indiceToken++;
            return token;
        } else {
            System.out.println("Fim dos tokens");

            JOptionPane.showMessageDialog(null, "Fim dos tokens");
            System.exit(0);


            return tokenaux;
        }


    }

    public void imprimeListaToken() {

        for (int i = 0; i < listadeTokens.size(); i++) {

            System.out.println("" + listadeTokens.get(i).getToken() + "\n");
        }

    }

    public LinkedList<String> getErros() {
        return erros;
    }
}
